#ifndef VOLUME_FRACTION_DATA_H
#define VOLUME_FRACTION_DATA_H

#include <map>
#include <cstddef>
#include <algorithm>

namespace ibm
{

template<typename T>
class VolumeFractionField
{
public:

	VolumeFractionField();

	VolumeFractionField(int widthX, int widthY, int widthZ);

	~VolumeFractionField();

public:

	VolumeFractionField& operator=(const VolumeFractionField& rhs);

	template<typename T2>
	VolumeFractionField& operator=(const VolumeFractionField<T2>& rhs);

	const T& operator[](int iX) const;

	T& operator[](int iX);

public:

	T& get(int iX, int iY, int iZ);

	int getNx() const { return nx; }

	int getNy() const { return ny; }

	int getNz() const { return nz; }

	void reset();


private:

	void allocateMemory();

	void releaseMemory();

private:

	T* raw_data;
	T*** field;

	int nx, ny, nz;

};

template<typename T>
VolumeFractionField<T>::VolumeFractionField()
:nx(0), ny(0), nz(0)
 {
	allocateMemory();
 }

template<typename T>
VolumeFractionField<T>::VolumeFractionField(int widthX, int widthY, int widthZ)
:nx(widthX), ny(widthY), nz(widthZ)
{
	allocateMemory();
}

/// Destroy the field data.
template<typename T>
VolumeFractionField<T>::~VolumeFractionField()
{
	releaseMemory();
}

template<typename T>
VolumeFractionField<T>& VolumeFractionField<T>::operator=(const VolumeFractionField<T>& rhs)
{
	int n = nx*ny*nz;
	for(int index; index != n; ++index)
			raw_data[index] = rhs.raw_data[index];

	return *this;
}

template<typename T>
template<typename T2>
VolumeFractionField<T>& VolumeFractionField<T>::operator=(const VolumeFractionField<T2>& rhs)
{
	for(int index; index != nx*ny*nz; ++index)
			raw_data[index] = (T)rhs.raw_data[index];

	return *this;
}

template<typename T>
const T& VolumeFractionField<T>::operator[](int iX) const
{
	return field[iX];
}

template<typename T>
T& VolumeFractionField<T>::operator[](int iX)
{
	return field[iX];
}

template<typename T>
T& VolumeFractionField<T>::get(int iX, int iY, int iZ)
{
	return field[iX][iY][iZ];
}

template<typename T>
void VolumeFractionField<T>::reset()
{
	for(int index = 0; index != nx*ny*nz; ++index)
		raw_data[index] = T();
}

template<typename T>
void VolumeFractionField<T>::allocateMemory()
{
	raw_data = new T[(std::size_t)nx*(std::size_t)ny*(std::size_t)nz];
	field = new T**[(std::size_t)nx];
	for (int iX = 0; iX != nx; ++iX)
	{
		field[iX] = new T* [(size_t)ny];

		for (int iY = 0; iY != ny; ++iY)
		{
			field[iX][iY] = raw_data + (std::size_t)nz*((std::size_t)iY+(std::size_t)ny*(std::size_t)iX);
		}

	}

	for(int index = 0; index != nx*ny*nz; ++index)
			raw_data[index] = T();
}

template<typename T>
void VolumeFractionField<T>::releaseMemory()
{
	delete [] raw_data; raw_data = 0;

	for (int iX = 0; iX != nx; ++iX)
	{
		delete [] field[iX];
	}

	delete [] field;
}

} // namespace ibm

#endif // VOLUME_FRACTION_DATA_H
